package org.csu.chatroom.Netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.util.CharsetUtil;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

@Component
 // 仅在 "dev" 环境下启动
public class NettyServer {
    private final int port = 8081;
    private final List<Channel> channels = new ArrayList<>();  // 保存所有客户端的连接
    private final Map<String, Room> rooms = new HashMap<>();  // 存储聊天室
    private final Map<Channel, Room> userRooms = new HashMap<>();  // 存储用户所在的聊天室
    private final Map<Channel, Long> lastHeartbeat = new HashMap<>(); // 存储每个客户端的心跳时间戳
    private final BlockingQueue<String> messageQueue = new LinkedBlockingQueue<>(); // 消息队列


    public void start() throws InterruptedException {

        // 启动消息处理线程
        new Thread(this::processMessages).start();


        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {

            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ChannelPipeline pipeline = ch.pipeline();

                            // 解码器：根据包头中的消息长度字段来处理粘包和半包
                            pipeline.addLast(new LengthFieldBasedFrameDecoder(
                                    8192,  // 最大帧大小
                                    0,     // 长度字段的偏移量，从包头的第 0 字节开始
                                    4,     // 长度字段的长度（消息体长度为 4 字节）
                                    0,     // 长度字段的增量，通常为 0
                                    4));   // 长度字段的数据起始位置，从包头的第 4 字节开始

                            // 将消息长度添加到包头
                            pipeline.addLast(new LengthFieldPrepender(4));  // 负责将消息长度写入包头
                            pipeline.addLast(new SimpleServerHandler(NettyServer.this));  // 这里传递
                        }
                    });

            ChannelFuture f = b.bind(port).sync();
            System.out.println("Netty 服务启动在端口 " + port);

            // 启动心跳检查线程
            new HeartbeatChecker(this).start();

            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }


    // 检查心跳
    public void checkHeartbeat() {
        long currentTime = System.currentTimeMillis();
        Iterator<Map.Entry<Channel, Long>> iterator = lastHeartbeat.entrySet().iterator();

        while (iterator.hasNext()) {
            Map.Entry<Channel, Long> entry = iterator.next();
            long lastTime = entry.getValue();

            // 超过 60 秒未收到心跳包，认为连接断开
            if (currentTime - lastTime > 60000) {
                Channel channel = entry.getKey();
                System.out.println("客户端 " + channel.remoteAddress() + " 超过 60 秒未收到心跳包，断开连接");
                channel.close();
                iterator.remove();
            }
        }
    }

    // 更新心跳时间戳
    public void updateHeartbeat(Channel channel) {
        lastHeartbeat.put(channel, System.currentTimeMillis());
    }



    public void addChannel(Channel channel) {
        channels.add(channel);
    }

    public void removeChannel(Channel channel) {
        channels.remove(channel);
    }

    // 创建聊天室
    public Room createRoom(String name) {
        Room room = new Room(name);
        rooms.put(name, room);
        return room;
    }

    // 获取聊天室
    public Room getRoom(String name) {
        return rooms.get(name);
    }

    // 处理消息的线程
    private void processMessages() {
        while (true) {
            try {
                // 从队列中取出消息并处理
                String message = messageQueue.take();
                // 处理消息逻辑
                System.out.println("处理消息: " + message);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    // 添加消息到队列
    public void addMessageToQueue(String message) {
        messageQueue.add(message);
    }


    public void broadcastMessage(String message) {
        for (Channel channel : channels) {
            channel.writeAndFlush(Unpooled.copiedBuffer(message, CharsetUtil.UTF_8));
        }
    }
}

